package com.browsesoft.syntax;

import java.io.IOException;
import java.io.InputStream;

/**
 * 单词解析器
 * <p>
 * Title:
 * </p>
 * <p>
 * Description:
 * </p>
 * <p>
 * Copyright: Copyright (c) 2003
 * </p>
 * <p>
 * Company:
 * </p>
 * 
 * @author not attributable
 * @version 1.0
 */
public class TokenParser implements java.io.Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 6698565984354488534L;

	/**
	 * 缓冲
	 */
	private byte[] buffer = new byte[1024];

	/**
	 * 实际从buffer中读到的字符数
	 */
	private int bufferCount = 0;

	/**
	 * buffer指针
	 */
	private int point = -1;

	/**
	 * 回退字符
	 */
	private byte backChar = -1;

	/**
	 * 输入流
	 */
	private InputStream is;

	/**
	 * 构造方法
	 * 
	 */
	public TokenParser() {
	}

	public TokenParser(InputStream is) throws IOException {
		this.is = is;
		bufferCount = is.read(buffer);
	}

	/**
	 * 从流中取到一个处理字符
	 * 
	 * @return
	 * @throws Exception
	 */
	public byte getChar() throws Exception {
		// 如果有回退字符
		// 则得到回退字符
		// 回退字符清空
		if (backChar != -1) {
			byte t = backChar;
			backChar = -1;
			return t;
		}
		// 如果在buffer结束处
		// 则重读一个buffer字符出来
		if (point == bufferCount - 1) {
			bufferCount = is.read(buffer);
			while (bufferCount == 0) {
				bufferCount = is.read(buffer);
			}
			// 如果读到文件结束
			// 则返回文件结束标志
			if (bufferCount == -1) {
				throw new StreamEndException();
			}
			point = -1;
		}
		// 否则从Buffer中读一个字符
		point++;
		return buffer[point];
	}

	/**
	 * 析取单词
	 * 
	 * @return
	 * @throws Exception
	 */
	/**
	 * 析取单詞
	 * 
	 * @return 单词
	 * @throws Exception
	 */
	public Token getWord() throws Exception {
		// 读掉空白
		byte t = getChar();
		while (t != -1 && Character.isWhitespace((char) t)) {
			t = getChar();
		}
		// 结束，返回结束类型
		if (t == -1) {
			return new Token("", "end");
		}
		// 是数字，组合数字串
		else if (Character.isDigit((char) t)) {
			return getNumber(t);
		}
		// 否则，如果是字符，则组合标识符
		else if (Character.isLowerCase((char) t)
				|| Character.isUpperCase((char) t)) {
			return getLaber(t);
		}
		// 否则，如果是运算符,则输出运算符
		else if (isOperator((char) t)) {
			return getOperator(t);
		}
		// 如果是标点符
		// 则直接析出标点符
		else if (isMark((char) t)) {
			String token = "" + (char) t;
			return new Token(token, "mark");
		} else {
			return new Token("", "end");
		}
	}

	/**
	 * 
	 * @param t
	 * @return
	 * @throws Exception
	 */
	public Token getNumber(byte t) throws Exception {
		// 把第一个数字添加进去
		String token = "" + (char) t;
		// 读下一个
		t = this.getChar();
		// 是数字，则循环组合数字
		while (Character.isDigit((char) t)) {
			token += (char) t;
			t = this.getChar();
		}
		putChar(t);
		return new Token(token, "number");
	}

	/**
	 * 
	 * @param t
	 */
	public void putChar(byte t) {
		backChar = t;
	}

	/**
	 * 
	 * @param t
	 * @return
	 * @throws Exception
	 */
	public Token getLaber(byte t) throws Exception {
		// 把第一个字符添进去
		String token = "" + (char) t;
		// 读下一个
		t = this.getChar();
		// 是字符或数字，则循环组合标识符
		while ((Character.isDigit((char) t))
				|| ((Character.isLowerCase((char) t) || (Character
						.isUpperCase((char) t))))) {
			token += (char) t;
			t = this.getChar();
		}
		putChar(t);
		return new Token(token, "lable");
	}

	public boolean isMark(char c) throws Exception {
		String strMark = "\".',;{}[]()";
		// 如果在标点符列表中能找到
		// 则返回true
		if (strMark.indexOf(c) != -1) {
			return true;
		} else {
			return false;
		}
	}

	public boolean isOperator(char c) throws Exception {
		String strOprator = "+-*/%&|!<>^~=";
		// 如果在标点符列表中能找到
		// 则返回true
		if (strOprator.indexOf(c) != -1) {
			return true;
		} else {
			return false;
		}
	}

	public Token getOperator(byte t) throws Exception {
		// 把第一个字符添进去
		String token = "" + (char) t;
		// 读下一个
		t = this.getChar();
		// 是操作符，则循环组合操作符
		while (isOperator((char) t)) {
			token += (char) t;
			t = this.getChar();
		}
		putChar(t);
		return new Token(token, "Operator");
	}

	public byte[] getBuffer() {
		return this.buffer;
	}

	public int getBufferCount() {
		return this.bufferCount;
	}

	public InputStream getIs() {
		return this.is;
	}

	/**
	 * 能够将“”内的内容解析出单词解析器
	 * 
	 * @return
	 * @throws Exception
	 */
	public Token parseWord() throws Exception {
		Token token = this.getWord();
		String text = "";
		// 如果是双引号，
		// 则取出两个双引号之间的内容作为一个单词
		if (token.getContext().equals("\"")) {
			// 如果没有到下一个双引号
			// 则将所得单词追加到当前词串尾部
			while (!(token.getContext().equals("\""))) {
				text += token.getContext();
			}
		}
		return new Token(text, "string");
	}
}